package websocket

import (
	"fmt"
	"net/http"
	"time"

	"data_service/models"
	"github.com/gorilla/websocket"
	"github.com/zeromicro/go-zero/core/logx"
	"gorm.io/gorm"
)

// 创建新的WebSocket服务器
func NewWebSocketServer(db *gorm.DB) *WebSocketServer {
	sqlDB, _ := db.DB()
	sqlDB.SetMaxIdleConns(10)
	sqlDB.SetMaxOpenConns(100)
	sqlDB.SetConnMaxLifetime(time.Hour)

	return &WebSocketServer{
		Rooms:     make(map[string]*Room),
		GameRooms: make(map[string]*GameRoom),
		upgrader: websocket.Upgrader{
			CheckOrigin: func(r *http.Request) bool {
				return true // 允许所有来源
			},
			ReadBufferSize:  1024,
			WriteBufferSize: 1024,
		},
		DB: db,
	}
}

// 获取房间（不自动创建）
func (s *WebSocketServer) GetRoom(id string) *Room {
	s.Mu.RLock()
	room, exists := s.Rooms[id]
	s.Mu.RUnlock()
	if exists {
		return room
	}
	return nil
}

// 获取游戏房间（不自动创建）
func (s *WebSocketServer) GetGameRoom(id string) *GameRoom {
	s.gameMu.RLock()
	room, exists := s.GameRooms[id]
	s.gameMu.RUnlock()
	if exists {
		return room
	}
	return nil
}

// 创建游戏房间
func (s *WebSocketServer) CreateGameRoom(name, gameType, creatorID, creatorName string, maxUsers int) string {
	roomID := fmt.Sprintf("%s-%d", gameType, time.Now().UnixNano())
	s.gameMu.Lock()
	defer s.gameMu.Unlock()
	room := &GameRoom{
		ID:          roomID,
		Name:        name,
		Type:        gameType,
		CreatorID:   creatorID,
		CreatorName: creatorName,
		Clients:     make(map[string]*Client),
		UserNames:   make(map[string]string),
		JoinTimes:   make(map[string]int64),
		Ready:       make(map[string]bool),
		MaxUsers:    maxUsers,
		wsServer:    s,
	}
	s.GameRooms[roomID] = room
	return roomID
}

// 获取或创建可加入的游戏房间
func (s *WebSocketServer) GetOrCreateGameRoomForJoin(gameType string) *GameRoom {
	s.gameMu.Lock()
	defer s.gameMu.Unlock()
	// 查找未满的游戏房间
	for _, room := range s.GameRooms {
		if room.Type == gameType && len(room.Clients) < room.MaxUsers {
			return room
		}
	}
	// 没有未满房间则新建
	return s.createDefaultGameRoom(gameType)
}

// 创建默认游戏房间
func (s *WebSocketServer) createDefaultGameRoom(gameType string) *GameRoom {
	roomID := fmt.Sprintf("%s-%d", gameType, time.Now().UnixNano())
	maxUsers := 2
	if gameType == "chat" {
		maxUsers = 20
	}
	room := &GameRoom{
		ID:       roomID,
		Name:     gameType,
		Type:     gameType,
		Clients:  make(map[string]*Client),
		MaxUsers: maxUsers,
		wsServer: s,
	}
	s.GameRooms[roomID] = room
	return room
}

// 创建房间支持自定义MaxUsers
func (s *WebSocketServer) CreateRoom(name, creatorID, creatorName string, maxUsers int) string {
	roomID := fmt.Sprintf("room-%d", time.Now().UnixNano())
	s.Mu.Lock()
	defer s.Mu.Unlock()
	room := &Room{
		ID:          roomID,
		Name:        name,
		CreatorID:   creatorID,
		CreatorName: creatorName,
		Clients:     make(map[string]*Client),
		UserNames:   make(map[string]string),
		JoinTimes:   make(map[string]int64),
		Ready:       make(map[string]bool),
		MaxUsers:    maxUsers,
		wsServer:    s,
	}
	s.Rooms[roomID] = room
	return roomID
}

// 向房间添加客户端
func (r *Room) AddClient(client *Client) {
	r.Mu.Lock()
	r.Clients[client.UserID] = client
	r.UserNames[client.UserID] = client.UserName
	r.JoinTimes[client.UserID] = time.Now().UnixNano()
	r.Ready[client.UserID] = false
	if r.destroyTimer != nil {
		r.destroyTimer.Stop()
		r.destroyTimer = nil
	}
	r.Mu.Unlock()

	// 清空empty_since
	// if r.wsServer != nil && r.wsServer.DB != nil {
	//	models.ClearRoomEmptySince(r.ID)
	// }
	logx.Infof("[AddClient] user %s(%s) joined room %s, now %d users", client.UserName, client.UserID, r.ID, len(r.Clients))
}

// 向游戏房间添加客户端
func (r *GameRoom) AddClient(client *Client) {
	r.mu.Lock()
	r.Clients[client.UserID] = client
	r.UserNames[client.UserID] = client.UserName
	r.JoinTimes[client.UserID] = time.Now().UnixNano()
	r.Ready[client.UserID] = false
	if r.destroyTimer != nil {
		r.destroyTimer.Stop()
		r.destroyTimer = nil
	}
	r.mu.Unlock()

	// 初始化游戏状态（如果需要）
	if r.GameState == nil {
		r.gameMu.Lock()
		r.GameState = &GameState{
			Status:  "waiting",
			Snakes:  make(map[string]*Snake),
			Foods:   []SnakeSegment{},
			Scores:  make(map[string]int),
			Ready:   make(map[string]bool),
			Players: make(map[string]*PlayerInfo),
		}
		r.gameMu.Unlock()
	}

	logx.Infof("[GameRoom.AddClient] user %s(%s) joined game room %s, now %d users", client.UserName, client.UserID, r.ID, len(r.Clients))
}

// 从房间移除客户端
func (r *Room) RemoveClient(client *Client) {
	if client == nil {
		logx.Error("[removeClient] 尝试移除空客户端")
		return
	}

	// 先获取必要信息，避免锁内执行过多操作
	userID := client.UserID
	userName := client.UserName

	r.Mu.Lock()
	if _, exists := r.Clients[userID]; exists {
		delete(r.Clients, userID)
		delete(r.UserNames, userID)
		delete(r.JoinTimes, userID)
		delete(r.Ready, userID)
	}
	empty := len(r.Clients) == 0
	clientCount := len(r.Clients)
	r.Mu.Unlock()

	// 安全关闭客户端连接和通道
	// 在锁外执行，避免死锁
	if client != nil && client.Send != nil {
		// 使用客户端锁保护关闭操作
		client.Mu.Lock()
		select {
		case <-client.Send:
			// 通道已关闭
		default:
			close(client.Send)
		}

		// 安全关闭WebSocket连接
		if client.Conn != nil {
			client.Conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "用户离开房间"))
			client.Conn.Close()
		}
		client.Mu.Unlock()
	}

	logx.Infof("[removeClient] user %s(%s) left room %s, now %d users", userName, userID, r.ID, clientCount)

	// 延迟一小段时间再广播，确保连接已正确关闭
	time.Sleep(100 * time.Millisecond)

	// 通知房间内其他用户有用户离开
	leaveMsg := Message{
		Type:     int(MessageTypeLeave),
		UserID:   userID,
		UserName: userName,
		Content:  fmt.Sprintf("%s 离开了房间", userName),
		Time:     time.Now().Unix(),
	}
	r.Broadcast(leaveMsg)

	// 自动销毁逻辑
	if empty {
		// 设置empty_since
		// if r.wsServer != nil && r.wsServer.DB != nil {
		//	if err := models.SetRoomEmptySince(r.ID, time.Now()); err != nil {
		//		logx.Errorf("设置房间empty_since失败: %v", err)
		//	}
		// }
		r.Mu.Lock()
		// 检查是否真的没有客户端
		if len(r.Clients) == 0 {
			if r.destroyTimer == nil {
				logx.Infof("[auto-destroy] 设置房间 %s 的自动销毁计时器（30秒）", r.ID)
				r.destroyTimer = time.AfterFunc(30*time.Second, func() {
					// 再次检查房间是否真的为空
					r.Mu.Lock()
					if len(r.Clients) > 0 {
						logx.Infof("[auto-destroy] 房间 %s 不再为空，取消自动销毁", r.ID)
						r.Mu.Unlock()
						return
					}
					r.Mu.Unlock()

					logx.Infof("[auto-destroy] room %s will be destroyed (no users)", r.ID)
					if r.wsServer != nil {
						r.wsServer.Mu.Lock()
						delete(r.wsServer.Rooms, r.ID)
						r.wsServer.Mu.Unlock()

						// 从数据库中删除房间
						// if r.wsServer.DB != nil {
						//	if err := models.DeleteRoomByID(r.ID); err != nil {
						//		logx.Errorf("[auto-destroy] failed to delete room %s from database: %v", r.ID, err)
						//	} else {
						//		logx.Infof("[auto-destroy] room %s deleted from database", r.ID)
						//	}
						// }
					}
					logx.Infof("[auto-destroy] room %s destroyed", r.ID)
				})
			}
		} else {
			// 如果检查发现其实有客户端，取消销毁计时器
			logx.Infof("[auto-destroy] 房间 %s 不为空 (客户端数: %d)，取消自动销毁", r.ID, len(r.Clients))
			if r.destroyTimer != nil {
				r.destroyTimer.Stop()
				r.destroyTimer = nil
			}
		}
		r.Mu.Unlock()
	}

	// 在 removeClient 里，移除用户后加上：
	// if r.wsServer != nil && r.wsServer.DB != nil {
	//	// 清理用户的准备状态和房间ID
	//	if err := models.UpdateUserReadyStatus(r.wsServer.DB, userID, "", false); err != nil {
	//		logx.Errorf("更新用户准备状态失败: %v", err)
	//	}
	// }
}

// 从游戏房间移除客户端
func (r *GameRoom) RemoveClient(client *Client) {
	if client == nil {
		logx.Error("[GameRoom.removeClient] 尝试移除空客户端")
		return
	}

	// 先获取必要信息，避免锁内执行过多操作
	userID := client.UserID
	userName := client.UserName

	r.mu.Lock()
	if _, exists := r.Clients[userID]; exists {
		delete(r.Clients, userID)
		delete(r.UserNames, userID)
		delete(r.JoinTimes, userID)
		delete(r.Ready, userID)
	}
	empty := len(r.Clients) == 0
	clientCount := len(r.Clients)
	r.mu.Unlock()

	// 安全关闭客户端连接和通道
	// 在锁外执行，避免死锁
	if client != nil && client.Send != nil {
		// 使用客户端锁保护关闭操作
		client.Mu.Lock()
		select {
		case <-client.Send:
			// 通道已关闭
		default:
			close(client.Send)
		}

		// 安全关闭WebSocket连接
		if client.Conn != nil {
			client.Conn.WriteMessage(websocket.CloseMessage, websocket.FormatCloseMessage(websocket.CloseNormalClosure, "用户离开游戏房间"))
			client.Conn.Close()
		}
		client.Mu.Unlock()
	}

	logx.Infof("[GameRoom.removeClient] user %s(%s) left game room %s, now %d users", userName, userID, r.ID, clientCount)

	// 延迟一小段时间再广播，确保连接已正确关闭
	time.Sleep(100 * time.Millisecond)

	// 通知房间内其他用户有用户离开
	leaveMsg := Message{
		Type:     int(MessageTypeLeave),
		UserID:   userID,
		UserName: userName,
		Content:  fmt.Sprintf("%s 离开了游戏房间", userName),
		Time:     time.Now().Unix(),
	}
	r.Broadcast(leaveMsg)

	// 停止游戏（如果需要）
	if clientCount <= 1 && r.GameState != nil && r.GameState.Status == "playing" {
		r.StopGame()
	}

	// 自动销毁逻辑
	if empty {
		// 设置empty_since
		if r.wsServer != nil && r.wsServer.DB != nil {
			if err := models.SetRoomEmptySince(r.ID, time.Now()); err != nil {
				logx.Errorf("设置游戏房间empty_since失败: %v", err)
			}
		}
		r.mu.Lock()
		// 检查是否真的没有客户端
		if len(r.Clients) == 0 {
			if r.destroyTimer == nil {
				logx.Infof("[GameRoom.auto-destroy] 设置游戏房间 %s 的自动销毁计时器（30秒）", r.ID)
				r.destroyTimer = time.AfterFunc(30*time.Second, func() {
					// 再次检查房间是否真的为空
					r.mu.Lock()
					if len(r.Clients) > 0 {
						logx.Infof("[GameRoom.auto-destroy] 游戏房间 %s 不再为空，取消自动销毁", r.ID)
						r.mu.Unlock()
						return
					}
					r.mu.Unlock()

					// 停止游戏（如果正在运行）
					r.StopGame()

					logx.Infof("[GameRoom.auto-destroy] game room %s will be destroyed (no users)", r.ID)
					if r.wsServer != nil {
						r.wsServer.gameMu.Lock()
						delete(r.wsServer.GameRooms, r.ID)
						r.wsServer.gameMu.Unlock()

						// 从数据库中删除房间
						if r.wsServer.DB != nil {
							if err := models.DeleteRoomByID(r.ID); err != nil {
								logx.Errorf("[GameRoom.auto-destroy] failed to delete game room %s from database: %v", r.ID, err)
							} else {
								logx.Infof("[GameRoom.auto-destroy] game room %s deleted from database", r.ID)
							}
						}
					}
					logx.Infof("[GameRoom.auto-destroy] game room %s destroyed", r.ID)
				})
			}
		} else {
			// 如果检查发现其实有客户端，取消销毁计时器
			logx.Infof("[GameRoom.auto-destroy] 游戏房间 %s 不为空 (客户端数: %d)，取消自动销毁", r.ID, len(r.Clients))
			if r.destroyTimer != nil {
				r.destroyTimer.Stop()
				r.destroyTimer = nil
			}
		}
		r.mu.Unlock()
	}

	// 在 removeClient 里，移除用户后加上：
	// if r.wsServer != nil && r.wsServer.DB != nil {
	//		// 清理用户的准备状态和房间ID
	//		if err := models.UpdateUserReadyStatus(r.wsServer.DB, userID, "", false); err != nil {
	//			logx.Errorf("更新用户准备状态失败: %v", err)
	//		}
	//	}
}
